package com.spica.platform.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.spica.platform.common.constant.CommonConstant;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import ognl.Ognl;
import ognl.OgnlContext;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

/**
 * 基于 Jackson 的 json 工具类
 */
@UtilityClass
@Slf4j
public class JsonUtil {
    private final  ObjectMapper MAPPER = new ObjectMapper();
    private static ObjectMapper snackToCamelMapper = new ObjectMapper();
    private static ObjectMapper objectMapper = new ObjectMapper();
    private static ObjectMapper objectAllMapper = new ObjectMapper();

     static{
    	MAPPER.setLocale(Locale.CHINA); 
        // 忽略在json字符串中存在，但是在java对象中不存在对应属性的情况
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 忽略空Bean转json的错误
        MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
        // 允许不带引号的字段名称
        MAPPER.configure(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES.mappedFeature(), true);
        // 允许单引号
        MAPPER.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
        // allow int startWith 0
        MAPPER.configure(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS.mappedFeature(), true);
        // 允许字符串存在转义字符：\r \n \t
        MAPPER.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
        // 在序列化时字段为NULL也进行序列化
        MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        // 使用驼峰式
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        // 使用bean名称
        MAPPER.enable(MapperFeature.USE_STD_BEAN_NAMING);
        //时区
        MAPPER.setTimeZone(TimeZone.getTimeZone(CommonConstant.DEFAULT_TIME_ZONE));
        // 所有日期格式都统一为固定格式
        MAPPER.setDateFormat(new SimpleDateFormat(CommonConstant.DATE_TIME_FORMAT_PATTERN));

         snackToCamelMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
         snackToCamelMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         snackToCamelMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
         snackToCamelMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

         //序列化的时候序列对象的所有属性
         objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
         //反序列化的时候如果多了其他属性,不抛出异常
         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         //忽略字段大小写
         objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
         //如果是空对象的时候,不抛异常
         objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

         objectAllMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
         //反序列化的时候如果多了其他属性,不抛出异常
         objectAllMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         //如果是空对象的时候,不抛异常
         objectAllMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    }

    /**
     * 对象转换为json字符串
     * @param o 要转换的对象
     */
    public  String toJSONString(Object o) {
        return toJSONString(o, false);
    }

    /**
     * 对象转换为json字符串
     * @param o 要转换的对象
     * @param format 是否格式化json
     */
    public  String toJSONString(Object o, boolean format) {
        try {
            if (o == null) {
                return "";
            }
            if (o instanceof Number) {
                return o.toString();
            }
            if (o instanceof String) {
                return (String)o;
            }
            if (format) {
                return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(o);
            }
            return MAPPER.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 字符串转换为指定对象
     * @param json json字符串
     * @param cls 目标对象
     */
    public  <T> T toObject(JsonNode json, Class<T> cls) {
        if(json == null || cls == null){
            return null;
        }
        return MAPPER.convertValue(json, cls);
    }

    /**
     * 字符串转换为指定对象，并增加泛型转义
     * 例如：List<Integer> test = toObject(jsonStr, List.class, Integer.class);
     * @param json json字符串
     * @param parametrized 目标对象
     * @param parameterClasses 泛型对象
     */
    public  <T> T toObject(String json, Class<?> parametrized, Class<?>... parameterClasses) {
        if(StringUtils.isEmpty(json) || parametrized == null){
            return null;
        }
        try {
            JavaType javaType = MAPPER.getTypeFactory().constructParametricType(parametrized, parameterClasses);
            return MAPPER.readValue(json, javaType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 字符串转换为指定对象
     * @param json json字符串
     * @param typeReference 目标对象类型
     */
    public  <T> T toObject(String json, TypeReference<T> typeReference) {
        if(StringUtils.isEmpty(json) || typeReference == null){
            return null;
        }
        try {
            return MAPPER.readValue(json, typeReference);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 字符串转换为指定对象
     * @param json json字符串
     * @param cls 目标对象
     */
    public  <T> T toObject(String json, Class<T> cls) {
        if(StringUtils.isEmpty(json) || cls == null){
            return null;
        }
        try {
            return MAPPER.readValue(json, cls);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 字符串转换为JsonNode对象
     * @param json json字符串
     */
    public  JsonNode parse(String json) {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            return MAPPER.readTree(json);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 对象转换为map对象
     * @param o 要转换的对象
     */
    public  <K, V> Map<K, V> toMap(Object o) {
        if (o == null) {
            return null;
        }
        if (o instanceof String) {
            return toObject((String)o, Map.class);
        }
        return MAPPER.convertValue(o, Map.class);
    }

    /**
     * json字符串转换为list对象
     * @param json json字符串
     */
    public  <T> List<T> toList(String json) {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            return MAPPER.readValue(json, List.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * json字符串转换为list对象，并指定元素类型
     * @param json json字符串
     * @param cls list的元素类型
     */
    public  <T> List<T> toList(String json, Class<T> cls) {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, cls);
            return MAPPER.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
    /**
    * @param json 原始的JSON数据
    * @param path OGNL规则表达式
    * @param clazz Value对应的目标类
    * @return clazz对应数据
    */
    public <T> T getValue(String json,String path,Class<T> clazz) {
    	try {
    		Map<String,Object> map = toObject(json, Map.class);
    		OgnlContext context = new OgnlContext();
    		context.setRoot(map);
    		T value = (T) Ognl.getValue(path, context,context.getRoot());
    		return value;
    	}catch (Exception e) {
    		throw new RuntimeException(e);
		}
    }

    public static <T> List<T> parseSnackJsonArray(String jsonString, Class<T> elementType) throws Exception {

        if (StringUtils.hasText(jsonString)) {

            TypeReference<List<T>> typeReference = new TypeReference<List<T>>() {
            };
            return snackToCamelMapper.readValue(jsonString, objectMapper.getTypeFactory()
                    .constructCollectionType(List.class, elementType));
        } else {
            return null;
        }
    }

    public static String toSnackJson(Object object) {
        try {
            return snackToCamelMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("to json exception", e);
            return "";
        }
    }

    public static <T> T parseSnackJson(String str, Class<T> clazz) {
        if (str == null || "".equals(str)) {
            return null;
        }
        try {
            return snackToCamelMapper.readValue(str, clazz);
        } catch (JsonProcessingException e) {
            log.error("parse exception: str={}", str, e);
            return null;
        }
    }

    public static <T> T parseSnackJson(String str, TypeReference<T> ref) {
        if (str == null || "".equals(str)) {
            return null;
        }
        try {
            return snackToCamelMapper.readValue(str, ref);
        } catch (JsonProcessingException e) {
            log.error("parse exception: str={}", str, e);
            return null;
        }
    }

    public static <T> T parseJsonObject(String str, Class<T> clazz) {
        if (str == null || "".equals(str)) {
            return null;
        }
        try {
            return objectMapper.readValue(str, clazz);
        } catch (JsonProcessingException e) {
            log.error("parse exception: str={}", str, e);
            return null;
        }
    }

    public static <T> List<T> parseJsonArray(String jsonString, Class<T> elementType) {

        if (StringUtils.hasText(jsonString)) {

            try {

                TypeReference<List<T>> typeReference = new TypeReference<List<T>>() {
                };
                return objectMapper.readValue(jsonString, objectMapper.getTypeFactory()
                        .constructCollectionType(List.class, elementType));

            } catch(Exception e) {

                log.error("parss error {}", jsonString, e);
                return null;
            }
        } else {
            return null;
        }
    }

    public static String toJsonStrWithAll(Object object) {
        try {
            return objectAllMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("to json exception", e);
            return "";
        }
    }

    public static String toJsonStr(Object object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("to json exception", e);
            return "";
        }
    }
}
